package com.property.demo.service.impl;

import com.property.demo.model.Vehicle;
import com.property.demo.model.Owner;
import com.property.demo.repository.VehicleRepository;
import com.property.demo.repository.OwnerRepository;
import com.property.demo.service.VehicleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class VehicleServiceImpl implements VehicleService {

    @Autowired
    private VehicleRepository vehicleRepository;
    
    @Autowired
    private OwnerRepository ownerRepository;

    @Override
    public List<Vehicle> findAll() {
        return vehicleRepository.findAll();
    }

    @Override
    public Page<Vehicle> findAll(Pageable pageable) {
        return vehicleRepository.findAll(pageable);
    }

    @Override
    public Page<Vehicle> findByFilters(Long ownerId, String licensePlate, String brand, String type, String status, Pageable pageable) {
        Specification<Vehicle> spec = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            if (ownerId != null) {
                Join<Vehicle, Owner> ownerJoin = root.join("owner");
                predicates.add(criteriaBuilder.equal(ownerJoin.get("id"), ownerId));
            }
            
            if (licensePlate != null && !licensePlate.isEmpty()) {
                predicates.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("licensePlate")), "%" + licensePlate.toLowerCase() + "%"));
            }
            
            if (brand != null && !brand.isEmpty()) {
                predicates.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("brand")), "%" + brand.toLowerCase() + "%"));
            }
            
            if (type != null && !type.isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("type"), type));
            }
            
            if (status != null && !status.isEmpty()) {
                predicates.add(criteriaBuilder.equal(root.get("status"), status));
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        return vehicleRepository.findAll(spec, pageable);
    }

    @Override
    public Optional<Vehicle> findById(Long id) {
        return vehicleRepository.findById(id);
    }

    @Override
    public Vehicle save(Vehicle vehicle) {
        if (vehicle.getOwner() != null && vehicle.getOwner().getId() != null) {
            Optional<Owner> owner = ownerRepository.findById(vehicle.getOwner().getId());
            owner.ifPresent(vehicle::setOwner);
        }
        
        return vehicleRepository.save(vehicle);
    }

    @Override
    public Vehicle update(Long id, Vehicle vehicleDetails) {
        Optional<Vehicle> optionalVehicle = vehicleRepository.findById(id);
        if (optionalVehicle.isPresent()) {
            Vehicle existingVehicle = optionalVehicle.get();
            
            if (vehicleDetails.getOwner() != null && vehicleDetails.getOwner().getId() != null) {
                Optional<Owner> owner = ownerRepository.findById(vehicleDetails.getOwner().getId());
                owner.ifPresent(existingVehicle::setOwner);
            }
            
            existingVehicle.setLicensePlate(vehicleDetails.getLicensePlate());
            existingVehicle.setBrand(vehicleDetails.getBrand());
            existingVehicle.setModel(vehicleDetails.getModel());
            existingVehicle.setColor(vehicleDetails.getColor());
            existingVehicle.setType(vehicleDetails.getType());
            existingVehicle.setParkingLocation(vehicleDetails.getParkingLocation());
            existingVehicle.setParkingPermitNumber(vehicleDetails.getParkingPermitNumber());
            existingVehicle.setPermitExpiryDate(vehicleDetails.getPermitExpiryDate());
            existingVehicle.setStatus(vehicleDetails.getStatus());
            existingVehicle.setRemarks(vehicleDetails.getRemarks());
            
            return vehicleRepository.save(existingVehicle);
        }
        return null;
    }

    @Override
    @Transactional
    public void delete(Long id) {
        vehicleRepository.deleteById(id);
    }

    @Override
    @Transactional
    public void deleteAll(List<Long> ids) {
        vehicleRepository.deleteAllById(ids);
    }

    @Override
    public List<Vehicle> findByOwnerId(Long ownerId) {
        return vehicleRepository.findByOwnerId(ownerId);
    }

    @Override
    public Optional<Vehicle> findByLicensePlate(String licensePlate) {
        return vehicleRepository.findByLicensePlate(licensePlate);
    }

    @Override
    public List<Vehicle> findByLicensePlateContaining(String licensePlate) {
        return vehicleRepository.findByLicensePlateContaining(licensePlate);
    }

    @Override
    public List<Vehicle> findByBrand(String brand) {
        return vehicleRepository.findByBrand(brand);
    }

    @Override
    public List<Vehicle> findByType(String type) {
        return vehicleRepository.findByType(type);
    }

    @Override
    public List<Vehicle> findByStatus(String status) {
        return vehicleRepository.findByStatus(status);
    }

    @Override
    public boolean existsByLicensePlate(String licensePlate) {
        return vehicleRepository.existsByLicensePlate(licensePlate);
    }
} 